#include <boost/algorithm/string/join.hpp>
#include <xscript/lexer/xastree.h>
#include <type/xitemint32.h>
#include <type/xitemfloat.h>
#include <type/xitemboolean.h>
#include <type/xitemstring.h>

uint32_t XASTreeNode::location() const
{
    for (auto& token : tokens) {
        return token->getLineNumber();
    }
    return 0;
}

std::wstring XASTreeNode::toString() const
{
    std::vector<std::wstring> items;
    items.push_back(L"(");
    for (auto& token : tokens) {
        items.push_back(token->getString());
    }
    items.push_back(L")");
    return boost::algorithm::join(items,std::wstring(L" "));
}

int32_t XASTreeInteger::getValue() const
{
    return token->asInteger()->getValue();
}

std::shared_ptr<XItem> XASTreeInteger::build(XVariableTable &table) const
{
    auto item = std::make_shared<XItemInt32>(getValue());
    item->setLineNumber(token->getLineNumber());
    table.addVariable(token->getString(),item);
    return item;
}

float XASTreeFloat::getValue() const
{
    return token->asFloat()->getValue();
}

std::shared_ptr<XItem> XASTreeFloat::build(XVariableTable &table) const
{
    auto item = std::make_shared<XItemFloat>(getValue());
    item->setLineNumber(token->getLineNumber());
    table.addVariable(token->getString(),item);
    return item;
}

std::wstring XASTreeString::getValue() const
{
    return token->asString()->getValue();
}

std::shared_ptr<XItem> XASTreeString::build(XVariableTable &table) const
{
    auto item = std::make_shared<XItemString>(getValue());
    item->setLineNumber(token->getLineNumber());
    table.addVariable(token->getString(),item);
    return item;
}

bool XASTreeBoolean::getValue() const
{
    return token->asBoolean()->getValue();
}

std::shared_ptr<XItem> XASTreeBoolean::build(XVariableTable &table) const
{
    auto item = std::make_shared<XItemBoolean>(getValue());
    item->setLineNumber(token->getLineNumber());
    table.addVariable(token->getString(),item);
    return item;
}

XASTreeBinary::XASTreeBinary(const XTokenList &items):
    XASTreeNode(items)
{
    assert(items.size() == 3 && L"XASTreeBinary childen count must be 3");
}

XASTree::XASTreePtr XASTreeBinary::getLeft() const
{
    return getChild(0);
}

XASTree::XASTreePtr XASTreeBinary::getRight() const
{
    return getChild(2);
}

std::wstring XASTreeBinary::getOperator() const
{
    return tokens.at(3)->getString();
}

XASTreeNegative::XASTreeNegative(const XTokenList &items):
    XASTreeNode(items)
{
    assert(items.size() == 1 && L"XASTreeNegative children must be 1");
}

XASTree::XASTreePtr XASTreeNegative::get() const
{
    return getChild(0);
}

int32_t XASTreeNegative::toInteger() const
{
    if(tokens.at(0)->asInteger())
        return -tokens.at(0)->asInteger()->getValue();
    return 0;
}

float XASTreeNegative::toFloat() const
{
    if(tokens.at(0)->asFloat())
        return -tokens.at(0)->asFloat()->getValue();
    return 0;
}

bool XASTreeNegative::isInteger() const
{
    return tokens.at(0)->asInteger() != nullptr;
}

XASTreeArray::XASTreeArray(const XTokenList &items):
    XASTreeNode(items)
{
}

size_t XASTreeArray::size() const
{
    return tokens.size();
}

XASTreeWhile::XASTreeWhile(const XTokenList &items):
    XASTreeNode(items)
{
}

XASTree::XASTreePtr XASTreeWhile::getCondition() const
{
    return getChild(0);
}

XASTree::XASTreePtr XASTreeWhile::getBody() const
{
    return getChild(1);
}

std::wstring XASTreeWhile::toString() const
{
    return std::wstring(L"(while ") + getCondition()->toString() + L" " + getBody()->toString() + L")";
}
